home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Lib / x400 / rasn.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  9.9 KB  |  485 lines

  1. /* rasn.c: incremental ASN1 reader */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Lib/x400/RCS/rasn.c,v 6.0 1991/12/18 20:25:37 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Lib/x400/RCS/rasn.c,v 6.0 1991/12/18 20:25:37 jpo Rel $
  9.  *
  10.  * $Log: rasn.c,v $
  11.  * Revision 6.0  1991/12/18  20:25:37  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. #include "util.h"
  19. #include "q.h"
  20. #include <isode/psap.h>
  21. #include <isode/cmd_srch.h>
  22.  
  23. extern PE        ps2pe_aux ();
  24.  
  25. static struct qbuf *qbase;
  26. static void add2qb ();
  27. static int check_external ();
  28. static int check_pserr (), qbproc ();
  29. static int attempt_parse (), read_octet_hdr (), read_octet ();
  30. static int proc_body (), proc_hdr (), proc_hdr_aux ();
  31.  
  32. IFP    asn_procfnx = proc_hdr;
  33. static IFP  hdrfnx, bodyfnx;
  34. static int    ext_type;
  35. #define PENDING (-2)
  36. static int bad = 0, oct_length;
  37.  
  38. void    asn_init (hf, bf, ext)
  39. IFP    hf, bf;
  40. int    ext;
  41. {
  42.     if (qbase)
  43.         qb_free (qbase);
  44.     qbase = NULL;
  45.     oct_length = bad = 0;
  46.     hdrfnx = hf;
  47.     bodyfnx = bf;
  48.     asn_procfnx = proc_hdr;
  49.     ext_type = ext;
  50. }
  51.  
  52.  
  53. static int proc_hdr (qp)
  54. struct qbuf *qp;
  55. {
  56.     char    *pestr;
  57.     int result;
  58.     int    len;
  59.  
  60.     add2qb (&qbase, qp);
  61.  
  62.     pestr = qb2str (qbase);
  63.     len = qbase -> qb_len;
  64.     result = attempt_parse (pestr, &len);
  65.     free (pestr);
  66.     switch (result) {
  67.         case PENDING:
  68.         return OK;
  69.         case DONE:
  70.         case NOTOK:
  71.         return result;
  72.         case OK:
  73.         break;
  74.     }
  75.         
  76.     PP_TRACE (("Header read, %d bytes", len));
  77.     if ((result = qbproc (qbase, &len, NULLIFP)) != OK)
  78.         return result;
  79.     asn_procfnx = proc_body;
  80.     return proc_body ((struct qbuf *)NULL);
  81. }
  82.  
  83. static int ext_length = 0;
  84.  
  85. static int attempt_parse (str, len)
  86. char    *str;
  87. int    *len;
  88. {
  89.     PS     ps;
  90.     PE    pe;
  91.     int    type;
  92.     char    *ptr;
  93.     int    len_left;
  94.     int retval = OK;
  95.  
  96.     if ((ps = ps_alloc (str_open)) == NULLPS) {
  97.         PP_LOG (LLOG_EXCEPTIONS, ("Can't allocate PS"));
  98.         return NOTOK;
  99.     }
  100.     if (str_setup (ps, str, *len, 1) == NOTOK) {
  101.         PP_LOG (LLOG_EXCEPTIONS, ("Can't bind str to PS"));
  102.         ps_free (ps);
  103.         return NOTOK;
  104.     }
  105.  
  106.     ext_length = 0;
  107.     if (ext_type) {
  108.         switch (ext_length = check_external (ps)) {
  109.             case PENDING:
  110.             ps_free (ps);
  111.             return PENDING;
  112.             case NOTOK:
  113.             ps_free (ps);
  114.             if (hdrfnx && (*hdrfnx) (NULLPE, NOTOK))
  115.                 return NOTOK;
  116.             bad = 1;
  117.             *len = 0;
  118.             return OK;
  119.             default:
  120.             break;
  121.         }
  122.     }
  123.  
  124.     ptr = ps -> ps_ptr;    /* save where we had got to */
  125.     len_left = *len - (ptr - str);
  126.  
  127.     if ((pe = ps2pe_aux (ps, 1, 0)) == NULLPE) {
  128.         ps_free (ps);
  129.         return check_pserr (ps);
  130.     }
  131.  
  132.     if (ps -> ps_cnt <= 0) {
  133.         ps_free (ps);
  134.         return PENDING;
  135.     }
  136.     switch (PE_ID(pe -> pe_class, pe -> pe_id)) {
  137.         case PE_ID (PE_CLASS_CONT, 0):
  138.         type = MT_UMPDU;
  139.         if (pe -> pe_len == PE_LEN_INDF)
  140.             ext_length += 2;
  141.         break;
  142.         case PE_ID (PE_CLASS_CONT, 1):
  143.         type = MT_DMPDU;
  144.         (void) str_setup (ps, ptr, len_left, 1);
  145.         break;
  146.         case PE_ID (PE_CLASS_CONT, 2):
  147.         type = MT_PMPDU;
  148.         (void) str_setup (ps, ptr, len_left, 1);
  149.         break;
  150.         default:
  151.         pe_free (pe);
  152.         ps_free (ps);
  153.         if (hdrfnx && (*hdrfnx) (NULLPE, NOTOK) != OK)
  154.             return NOTOK;
  155.         bad = 1;
  156.         *len = 0;
  157.         return OK;
  158.     }
  159.     pe_free (pe);
  160.  
  161.     if ((pe = ps2pe(ps)) == NULLPE)
  162.         return check_pserr (ps);
  163.  
  164.     if (hdrfnx && (*hdrfnx) (pe, type) != OK)
  165.         retval = NOTOK;
  166.     else 
  167.         retval = type == MT_UMPDU ? OK : DONE;
  168.  
  169.     *len -= ps -> ps_cnt;
  170.     ps_free (ps);
  171.     pe_free (pe);
  172.     return retval;
  173. }
  174.  
  175. /* ARGSUSED */
  176. static int proc_done (qb)
  177. struct qbuf *qb;
  178. {
  179.     PP_TRACE(("proc_done()"));
  180.     return DONE;
  181. }
  182.  
  183. static int proc_body (qp)
  184. struct qbuf *qp;
  185. {
  186.     int    i;
  187.     static int count, used;
  188.     
  189.     if (qp)
  190.         add2qb (&qbase, qp);
  191.     if (bad) {
  192.         i = qbase -> qb_len;
  193.         return qbproc (qbase, &i, bodyfnx);
  194.     }
  195.  
  196.     if (qbase -> qb_len && count > 0)
  197.         if ((i = qbproc (qbase, &count, bodyfnx)) != OK)
  198.             return i;
  199.  
  200.     for (;qbase -> qb_len > 0;) {
  201.         char *pestr = qb2str (qbase);
  202.         used = 0;
  203.         i = read_octet_hdr (pestr, qbase -> qb_len,
  204.                     &count, &used);
  205.         free (pestr);
  206.     
  207.         switch (i) {
  208.             case DONE:
  209.             (void) qbproc (qbase, &used, NULLIFP);
  210.             if (qbase -> qb_len - ext_length > 0) {
  211.                 PP_LOG(LLOG_EXCEPTIONS,
  212.                        ("Trailing garbage (%d bytes) on end of PDU",
  213.                     qbase -> qb_len - used));
  214.             }
  215.             asn_procfnx = proc_done;
  216.             return DONE;
  217.             case NOTOK:
  218.             return NOTOK;
  219.             case PENDING:
  220.             return OK;
  221.             case OK:
  222.             (void) qbproc (qbase, &used, NULLIFP);
  223.             if ((i = qbproc (qbase, &count, bodyfnx)) != OK)
  224.                 return i;
  225.             if (qbase -> qb_len <= 0)
  226.                 return OK;
  227.             break;
  228.         }
  229.     }
  230.     return OK;
  231. }
  232.  
  233.  
  234. static int check_external (ps)
  235. PS    ps;
  236. {
  237.     PE    pe;
  238.     int extra = 0;
  239.     char *psptr = ps -> ps_ptr;
  240.  
  241.     /* EXTERNAL Wrapper */
  242.     if ((pe = ps2pe_aux (ps, 1, 0)) == NULLPE)
  243.         return check_pserr (ps);
  244.  
  245.     if (PE_ID (pe -> pe_class, pe -> pe_id) !=
  246.         PE_ID (PE_CLASS_UNIV, PE_CONS_EXTN)) {
  247.         PP_LOG (LLOG_EXCEPTIONS,
  248.             ("Missing EXTERNAL wrapper; found %s/%d",
  249.              pe_classlist[pe -> pe_class], pe -> pe_id));
  250.         pe_free (pe);
  251.         return NOTOK;
  252.     }
  253.     if (pe -> pe_len == PE_LEN_INDF)
  254.         extra += 2;
  255.     pe_free (pe);
  256.  
  257.     if ((pe = ps2pe (ps)) == NULLPE)
  258.         return check_pserr (ps);
  259.  
  260.     if (PE_ID (pe -> pe_class, pe -> pe_id) !=
  261.         PE_ID (PE_CLASS_UNIV, PE_PRIM_INT)) {
  262.         PP_LOG (LLOG_EXCEPTIONS,
  263.             ("Missing External ID, found %s/%d",
  264.              pe_classlist[pe -> pe_class], pe -> pe_id));
  265.         pe_free (pe);
  266.         return NOTOK;
  267.     }
  268.     pe_free (pe);
  269.  
  270.     /* ANY Context 0 wrapper */
  271.     if ((pe = ps2pe_aux (ps, 1, 0)) == NULLPE)
  272.         return check_pserr (ps);
  273.  
  274.     if (PE_ID (pe -> pe_class, pe -> pe_id) !=
  275.         PE_ID (PE_CLASS_CONT, 0)) {
  276.         PP_LOG (LLOG_EXCEPTIONS,
  277.             ("Not an EXTERNAL ANY type; found %s/%d",
  278.              pe_classlist[pe -> pe_class], pe -> pe_id));
  279.         pe_free (pe);
  280.         return NOTOK;
  281.     }
  282.     if (pe -> pe_len == PE_LEN_INDF)
  283.         extra += 2;
  284.     pe_free (pe);
  285.     PP_TRACE (("%d bytes read, %d extra at end...",
  286.            ps -> ps_ptr - psptr, extra));
  287.     /* OK EXTERNAL checks out. */
  288.     return extra;
  289. }
  290.  
  291. static int qbproc (q, len, fnx)
  292. struct qbuf *q;
  293. int    *len;
  294. IFP    fnx;
  295. {
  296.     struct qbuf *qp;
  297.     int    i;
  298.  
  299.     if (q == NULL || q -> qb_len <= 0)
  300.         return OK;
  301.     if (q -> qb_len != q ->qb_forw -> qb_len &&
  302.         qb_pullup (q) == NOTOK)
  303.         adios (NULLCP, "qb_pullup failed");
  304.  
  305.     for (qp = NULL; *len > 0; ) {
  306.         if (qp == NULL &&
  307.             (qp = q -> qb_forw) == q)
  308.             break;
  309.         i = min(qp -> qb_len, *len);
  310.         if (fnx) {
  311.             int result;
  312.             result = (*fnx) (qp -> qb_data, i);
  313.             if (result != OK)
  314.                 return result;
  315.         }
  316.         *len -= i;
  317.         qp -> qb_data += i;
  318.         qp -> qb_len -= i;
  319.         q -> qb_len -= i;
  320.         if (qp -> qb_len <= 0) {
  321.             remque (qp);
  322.             free ((char *)qp);
  323.             qp = NULL;
  324.         }
  325.     }
  326.     return OK;
  327. }
  328.  
  329. static void add2qb (qpp, qp)
  330. struct qbuf **qpp, *qp;
  331. {
  332.     struct qbuf *q;
  333.  
  334.     if (*qpp == NULL) {
  335.         *qpp = (struct qbuf *) smalloc (sizeof *qp);
  336.         bzero ((char *)*qpp, sizeof **qpp);
  337.         (*qpp) -> qb_forw = (*qpp) -> qb_back = *qpp;
  338.     }
  339.     for (q = qp -> qb_forw; q != qp; q = qp -> qb_forw) {
  340.         remque (q);
  341.         insque (q, (*qpp) -> qb_back);
  342.         (*qpp) -> qb_len += q -> qb_len;
  343.         qp -> qb_len -= q -> qb_len;
  344.     }
  345. }
  346.  
  347. static int read_octet_hdr (str, len, countp, usedp)
  348. char    *str;
  349. int    len;
  350. int    *countp;
  351. int    *usedp;
  352. {
  353.     static PS ps;
  354.  
  355.     *usedp = 0;
  356.     if (len < 1)
  357.         return OK;
  358.     if (ps == NULLPS)
  359.         if ((ps = ps_alloc (str_open)) == NULLPS) {
  360.             PP_LOG (LLOG_EXCEPTIONS, ("Can't setup PS"));
  361.             return NOTOK;
  362.         }
  363.     if (str_setup (ps, str, len, 1) == NOTOK) {
  364.         PP_LOG (LLOG_EXCEPTIONS, ("Can't attach string to PS"));
  365.         return NOTOK;
  366.     }
  367.  
  368.     return read_octet (ps, countp, usedp);
  369. }
  370.  
  371. #define MAXSTACK 100
  372. static int stackidx = -1;
  373. static struct stack {
  374. #define STACK_EOC 1
  375. #define STACK_LEN 2
  376.     int     type;
  377.     int    len;
  378. } mystack[MAXSTACK];
  379.  
  380. static int read_octet (ps, countp, usedp)
  381. PS    ps;
  382. int    *countp;
  383. int    *usedp;
  384. {
  385.     PE    pe;
  386.     char    *psptr;
  387.  
  388.     PP_TRACE (("read_octet() stackidx = %d u=%d c=%d ol=%d", stackidx,
  389.            *usedp, *countp, oct_length));
  390.     if (stackidx >= 0 && mystack[stackidx].type == STACK_LEN &&
  391.         mystack[stackidx].len <= oct_length) {
  392.         stackidx --;
  393.         PP_TRACE (("read_octet length done, poping stack"));
  394.         if (stackidx < 0)
  395.             return DONE;
  396.         else
  397.             return read_octet (ps, countp, usedp);
  398.     }
  399.  
  400.     psptr = ps -> ps_ptr;
  401.     if ((pe = ps2pe_aux (ps, 1, 0)) == NULLPE)
  402.         return check_pserr (ps);
  403.  
  404.     if (pe -> pe_class == PE_CLASS_UNIV &&
  405.         pe -> pe_id == PE_UNIV_EOC) {
  406.         pe_free (pe);
  407.         PP_TRACE (("stackidx %d, type=%d", stackidx,
  408.                mystack[stackidx].type));
  409.         if (stackidx < 0 || mystack[stackidx].type != STACK_EOC) {
  410.             PP_LOG (LLOG_EXCEPTIONS, ("Unexpected EOC string"));
  411.             return NOTOK;
  412.         }
  413.         PP_TRACE (("read_octet EOC found, poping stack"));
  414.         *usedp += ps -> ps_ptr - psptr;
  415.         oct_length += ps -> ps_ptr - psptr;
  416.         stackidx --;
  417.         if (stackidx == -1) {
  418.             PP_TRACE (("read_octet used %d", *usedp));
  419.             return DONE;
  420.         }
  421.         else
  422.             return  read_octet (ps, countp, usedp);
  423.     }
  424.     
  425.     if (pe -> pe_class != PE_CLASS_UNIV ||
  426.         pe -> pe_id != PE_PRIM_OCTS) {
  427.         PP_LOG (LLOG_EXCEPTIONS,
  428.             ("Not an OCTET STRING expecting %s/%d got %s/%d",
  429.              pe_classlist[PE_CLASS_UNIV], PE_PRIM_OCTS,
  430.              pe_classlist[pe -> pe_class], pe -> pe_id));
  431.         return NOTOK;
  432.     }
  433.     if (pe -> pe_form != PE_FORM_PRIM) {
  434.         *usedp += ps -> ps_ptr - psptr;
  435.         oct_length += ps -> ps_ptr - psptr;
  436.         if (stackidx >= MAXSTACK - 1) {
  437.             PP_LOG (LLOG_EXCEPTIONS, ("Internal stack overflow"));
  438.             return NOTOK;
  439.         }
  440.         stackidx ++;
  441.         if (pe -> pe_len == PE_LEN_INDF) {
  442.             PP_TRACE (("read_octet cons INDF found, pushing..."));
  443.             mystack[stackidx].type = STACK_EOC;
  444.         }
  445.         else {
  446.             PP_TRACE (("read_octet cons len %d found pushing",
  447.                    pe -> pe_len));
  448.             mystack[stackidx].type = STACK_LEN;
  449.             mystack[stackidx].len = oct_length + pe -> pe_len;
  450.         }
  451.         return read_octet (ps, countp, usedp);
  452.     }
  453.     stackidx ++;
  454.     mystack[stackidx].type = STACK_LEN;
  455.     mystack[stackidx].len = oct_length + pe -> pe_len;
  456.     *countp = pe -> pe_len;
  457.     oct_length += pe -> pe_len;
  458.     *usedp += ps -> ps_ptr - psptr;
  459.     PP_TRACE (("read_octet used %d count %d ol=%d", *usedp, *countp,
  460.            oct_length));
  461.     pe_free (pe);
  462.     return OK;
  463. }
  464.  
  465. static int check_pserr (ps)
  466. PS    ps;
  467. {
  468.     int    retval = PENDING;
  469.  
  470.     switch (ps -> ps_errno) {
  471.         case PS_ERR_EOF:
  472.         case PS_ERR_EOFLEN:
  473.         case PS_ERR_EOFID:
  474.         case PS_ERR_NONE:
  475.         break;
  476.  
  477.         default:
  478.         PP_LOG (LLOG_EXCEPTIONS, ("ps2pe error: %s",
  479.                       ps_error (ps -> ps_errno)));
  480.         retval = NOTOK;
  481.         break;
  482.     }
  483.     return retval;
  484. }
  485.